#include "WebCodecsThread.hpp"

#include <emscripten.h>
#include <emscripten/fetch.h>

#include "EyerCore/EyerCore.hpp"
#include "EyerAV/EyerAV.hpp"
#include "EyerAVC/EyerAVC.hpp"

extern "C"
{

EMSCRIPTEN_KEEPALIVE int JSEvent_WebCodecs_VideoDecoder_init();
EMSCRIPTEN_KEEPALIVE int JSEvent_WebCodecs_VideoDecoder_decode(int decoderIndex, uint8_t * buf, int size, int pts);
EMSCRIPTEN_KEEPALIVE int JSEvent_WebCodecs_VideoDecoder_flush(int decoderIndex);

}

namespace Eyer
{
    void WebCodecsThread::event_loop(void * arg)
    {
        WebCodecsThread * eventloop = (WebCodecsThread *)arg;
        eventloop->eventLoop();
    }

    int WebCodecsThread::eventLoop() {
        if(reader == nullptr){
            reader = new EyerAVReader("/lg.mp4");

            int ret = reader->Open();
            if(ret){
            }

            videoStreamIndex = reader->GetVideoStreamIndex();
            if(videoStreamIndex < 0){
            }

            EyerAVStream videoStream = reader->GetStream(videoStreamIndex);
            avBitstreamFilter = new Eyer::EyerAVBitstreamFilter(EyerAVBitstreamFilterType::H264_MP4TOANNEXB, videoStream);

            decodeIndex = JSEvent_WebCodecs_VideoDecoder_init();
            EyerLog("Decode Index: %d\n", decodeIndex);
        }

        EyerAVPacket packet;
        int ret = reader->Read(packet);
        if(ret){
            JSEvent_WebCodecs_VideoDecoder_flush(decodeIndex);
            return 0;
        }

        if(packet.GetStreamIndex() != videoStreamIndex){
            return 0;
        }

        avBitstreamFilter->SendPacket(packet);
        while(1) {
            EyerAVPacket annexBPacket;
            ret = avBitstreamFilter->RecvPacket(annexBPacket);
            if (ret) {
                break;
            }

            uint8_t *data = annexBPacket.GetDatePtr();
            int dataLen = annexBPacket.GetSize();

            JSEvent_WebCodecs_VideoDecoder_decode(decodeIndex, data, dataLen, (int) annexBPacket.GetPTS());
        }
        return 0;
    }

    void WebCodecsThread::Run()
    {
        EyerLog("WebCodecsThread Start\n");

        EyerString url = "https://127.0.0.1/websdk/demo/res/Bytedance_avc_AV_PIX_FMT_YUV420P_1920x1080_30fps_300s_fdkaac_48000_stereo.mov";

        emscripten_fetch_attr_t attr;
        emscripten_fetch_attr_init(&attr);
        strcpy(attr.requestMethod, "GET");
        attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY | EMSCRIPTEN_FETCH_SYNCHRONOUS;
        emscripten_fetch_t * fetch = emscripten_fetch(&attr, url.c_str()); // Blocks here until the operation is complete.
        if (fetch->status == 200) {
            printf("Finished downloading %llu bytes from URL %s.\n", fetch->numBytes, fetch->url);

            FILE * f = fopen("/lg.mp4", "wb");
            fwrite(fetch->data, 1, fetch->numBytes, f);
            fclose(f);
        } else {
            printf("Downloading %s failed, HTTP failure status code: %d.\n", fetch->url, fetch->status);
        }
        emscripten_fetch_close(fetch);



        emscripten_set_main_loop_arg(event_loop, this, 0, 0);

        /*
        Eyer::EyerAVReader reader("/lg.mp4");
        int ret = reader.Open();
        if(ret){
            return;
        }

        int videoStreamIndex = reader.GetVideoStreamIndex();
        if(videoStreamIndex < 0){
            return;
        }

        EyerAVStream videoStream = reader.GetStream(videoStreamIndex);

        Eyer::EyerAVBitstreamFilter avBitstreamFilter(EyerAVBitstreamFilterType::H264_MP4TOANNEXB, videoStream);

        int decodeIndex = JSEvent_WebCodecs_VideoDecoder_init();
        EyerLog("Decode Index: %d\n", decodeIndex);

        while(1){
            EyerAVPacket packet;
            ret = reader.Read(packet);
            if(ret){
                break;
            }

            if(packet.GetStreamIndex() != videoStreamIndex){
                continue;
            }

            avBitstreamFilter.SendPacket(packet);
            while(1){
                EyerAVPacket annexBPacket;
                ret = avBitstreamFilter.RecvPacket(annexBPacket);
                if(ret){
                    break;
                }

                uint8_t * data = annexBPacket.GetDatePtr();
                int dataLen = annexBPacket.GetSize();

                JSEvent_WebCodecs_VideoDecoder_decode(decodeIndex, data, dataLen, (int)annexBPacket.GetPTS());



                Eyer::EyerAnnexBParse annexBParse(data, dataLen);
                while(1){
                    EyerNALUData naluData;
                    ret = annexBParse.ReadNALU(naluData);
                    if(ret){
                        break;
                    }

                    if(naluData.GetNALUType() == NALUType::NALU_TYPE_SPS){
                        EyerLog("AnnexB Packet: %s\n", naluData.GetNALUType().GetName().c_str());

                        uint8_t * nalu = naluData.naluBuffer.GetPtr();
                        nalu = nalu + naluData.startCodeLen + 1;
                        char headerStr[128];
                        sprintf(headerStr, "%02x%02x%02x", nalu[0],  nalu[1],  nalu[2]);
                        EyerLog("%s\n", headerStr);
                    }
                }

            }
        }

        reader.Close();
         */

        EyerLog("WebCodecsThread End\n");
    }
}